#pragma once

#include<iostream>
#include<string>
#include <sstream>
#include <memory>
#include <jsoncpp/json/json.h>


//给序列化后的字符串（数据）添加报头和标记符号便于解决tcp面向字节流的拷贝不充分的问题
//标记符号
const std::string Sep = "\r\n";
//加报头后的格式：
// {json} -> len\r\n{json}\r\n

//加
bool Encode(std::string &message)
{
    if(message.size() == 0) return false;
    std::string package = std::to_string(message.size()) + Sep + message + Sep;
    message = package;
    return true;
}

//从缓冲区拷贝后的字符串格式：
// len\r\n{json}\r\n
// 123\r\n{json}\r\n -> {json}
// 123\r\n
// 123\r\n{json
// 123\r\n{json}\r
// 123\r\n{json}\r\n123\r\n{js

//服务器识别
bool Decode(std::string &package, std::string *content)
{
    //先找标记符
    auto pos = package.find(Sep);
    if(pos == std::string::npos) return false;
    //找到后看标记符前的数字知道报文的大小
    std::string content_length_str = package.substr(0, pos);
    int content_length = std::stoi(content_length_str);
    //最小的序列化后的字符串大小
    int full_length = content_length_str.size() + content_length + 2*Sep.size();

    if(package.size() < full_length)
        return false;
    
    *content = package.substr(pos + Sep.size(), content_length);

    // package erase
    package.erase(0, full_length); // 后续写网络代码再来研究
    return true;
}

//利用Json完成序列化的格式协议（格式：xml/Json...）
//客户端
//_x _oper _y
class Request
{
public:
    Request() : _x(0), _y(0), _oper(0)
    {}
    Request(int x,int y,char oper):_x(x) ,_y(y) ,_oper(oper)
    {}

    //序列化Json工厂形式
    bool Serialize(std::string &out_string)
    {
        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper;

        //toStyledString 形式：
        // std::string s = root.toStyledString();

        //FastWriter形式
        // Json::FastWriter writer;
        // std::string s = writer.write(root);

        //StreamWriter形式：
        Json::StreamWriterBuilder wb;
        std::unique_ptr<Json::StreamWriter> w(wb.newStreamWriter());
        std::stringstream ss;
        w->write(root, &ss);
        out_string = ss.str();
        return true;
    }

    //反序列化
    bool Deserialize(std::string &in_string)
    {
        Json::Value root;
        Json::Reader reader;
        //读序列化后的字符串
        bool parsingSuccessful = reader.parse(in_string,root);
        if(!parsingSuccessful)
        {
            std::cout << "Failed to parse Json: " << reader.getFormattedErrorMessages() << std::endl;
            return false;
        }

        _x = root["x"].asInt();
        _y = root["y"].asInt();
        _oper = root["oper"].asInt();

        return true;

    }

    void Print()
    {
        std::cout << _x << std::endl;
        std::cout << _oper << std::endl;
        std::cout << _y << std::endl;
    }

    int X() const { return _x; }

    int Y() const { return _y; }

    char Oper() const { return _oper; }

private:
    int _x;
    int _y;
    char _oper;
};

//服务器
class Response
{
public:
    Response() : _result(0), _code(0)
    {
    }
    Response(int result, int code) : _result(result), _code(code)
    {}

    //序列化
    bool Serialize(std::string &out_string)
    {
        Json::Value root;
        root["result"] = _result;
        root["code"] = _code;

        Json::StreamWriterBuilder wb;
        std::unique_ptr<Json::StreamWriter> w(wb.newStreamWriter());
        std::stringstream ss;
        w->write(root, &ss);
        out_string = ss.str();
        return true;
    }

    //反序列化
    bool Deserialize(std::string &in_string)
    {
        Json::Value root;
        Json::Reader reader;
        //读序列化后的字符串
        bool parsingSuccessful = reader.parse(in_string,root);
        if(!parsingSuccessful)
        {
            std::cout << "Failed to parse Json: " << reader.getFormattedErrorMessages() << std::endl;
            return false;
        }

        _result = root["result"].asInt();
        _code = root["code"].asInt();

        return true;
    }

    int Result() const { return _result; }

    int Code() const { return _code; }

    void SetResult(int res) {_result = res;}

    void SetCode(int c) {_code = c;}

private:
    int _result;//计算结果
    int _code;  //错误码0，1，2，3，4
};







